home *** CD-ROM | disk | FTP | other *** search
- Path: fido.asd.sgi.com!austern
- From: gregor@netcom.com (Greg Colvin)
- Newsgroups: comp.std.c++
- Subject: auto_ptr idioms
- Date: 08 Feb 1996 10:10:20 PST
- Organization: Netcom Online Communications Services (408-241-9760 login: guest)
- Approved: austern@isolde.mti.sgi.com
- Message-ID: <gregorDMG2B0.5vw@netcom.com>
- NNTP-Posting-Host: isolde.mti.sgi.com
- X-Original-Date: Thu, 8 Feb 1996 06:35:24 GMT
- Apparently-To: comp-std-c++@uunet.uu.net
- X-Auth: PGPMoose V1.1 PGP comp.std.c++
- iQBVAwUBMRo8oUy4NqrwXLNJAQFsuwH+IThah/4FrTesgjmjWk6jmM3RN9SoJqBg
- vVx2wNZLplzIY9xGY0Vy41fmUf7LWcStyEu2VX1y9LpoyMdYREWfOw==
- =eDcn
- Originator: austern@isolde.mti.sgi.com
-
- Many of the comments I have received on auto_ptr seem to be based on a
- desire to be able to use an auto_ptr "just like an ordinary pointer".
- I share this desire, but I did not design auto_ptr to satisfy it. My
- gc_ptr and counted_ptr proposals came much closer, but did not satisfy
- the committee. Rather, auto_ptr was designed to provide exception safety in
- just three very restricted idioms. I hope a little motivation and history
- will clarify the issues, and perhaps convince you of the need for the changes
- I am proposing.
-
- The fundamental problem for exception safety was fixing code like this:
- void g(T*);
- void f() {
- T* p(new T);
- g(p);
- delete p;
- }
- If the function g() throws an exception then delete p will not be called.
- Of course you could write this instead:
- void g(T*);
- void f() {
- T* p(new T);
- try {
- g(p);
- } catch(...) {
- delete p;
- throw;
- }
- delete p;
- }
- But would you want to? Not me. The auto_ptr template provides a simpler
- "resource acquistion is initialization" idiom:
- void g(T*);
- void f() {
- auto_ptr<T> p(new T);
- g(&*p);
- }
- All that auto_ptr was absolutely *required* to do is support this idiom, and
- that is all my original auto_ptr proposal did. In this it was like earlier
- sugestions by John Skaller and Steve Rumbsy. However, Bill Gibbons of
- Taligent reported: that Taligent had considerable experience with a class
- much like auto_ptr, that they found that a copy semantics essential, and
- that the appropriate semantics was to transfer ownership.
-
- Given a copy semantics, two other useful idioms become possible:
-
- // sink() is responsible for deleting its argument
- void sink(auto_ptr<T>);
-
- // source() returns a pointer that its caller is responsible for deleting
- auto_ptr<T> source();
-
- Given careful use of auto_ptr (no calls to get(), reset(), or release()) the
- sink() function is sure to delete its argument, and the caller of source() is
- sure to delete its returned pointer. So far so good.
-
- Unfortunately, the current semantics of C++ do not allow the following:
- auto_ptr<T> p(source());
- This is because the copy semantics for auto_ptr are destructive (non-const),
- but passing the value returned by source() to the copy constructor requires
- a temporary, which cannot be passed to auto_ptr(auto_ptr&) for reasons that
- remain obscure to me (and to all the compilers I own), but that are spelled
- out in the ARM (8.4.3).
-
- To fix the source() idiom I propose to make the auto_ptr copy semantics
- non-destructive. Currently, when you copy an auto_ptr the source ends up
- holding a null pointer. I propose instead to leave the source pointer
- unchanged, but transfer ownership of the object pointed to. Arguably, a
- change in ownership is not a change in the state of any particular auto_ptr,
- and no public function will tell you which auto_ptr owns a particular pointer,
- so the copy constructor and assignment operator are "logically" const, and we
- can use mutable state to implement them with const arguments.
-
- Note that this change does not affect the three idioms above at all: you
- would write the same code after the change as you would now. Still, the
- change is not for free. Some criticisms and my response follow.
-
- Performance. A little more space and time will be needed to represent the
- pointer value and the object ownership separately.
- True, but the cost is small even for portable implementations, and can be
- made even smaller in non-portable ones. I think the cost is worth it.
-
- Safety. Now, an auto_ptr cannot be a dangling pointer, although it can be
- null. With this change a non-null auto_ptr might be a dangling pointer.
- True, but this is not a problem for the idioms auto_ptr is designed to
- support. The problem was to be sure that pointers held in automatic
- variables are deleted when exceptions are thrown, not to prevent dangling
- pointers. Regardless, dereferencing a null pointer is no less undefined
- than dereferencing a dangling pointer, and the available memory utilities
- like Purify, BoundsChecker, and Great Circle will handle either case
- equally well.
-
- Convenience. Now, I can use get() to test whether an auto_ptr is still
- valid. With this change I cannot.
- True, but again not a problem for the above idioms. In my opinion, the
- effective use of auto_ptr requires careful design. Questions like whether
- an auto_ptr is an owner or is valid must be answerable statically, by
- design, any attempt to answer them at runtime will be fraught with peril.
- If you really need to answer these questions at runtime then you need
- some form of reference counting or tracing garbage collection.
- ---
- [ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
- Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
- in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
-